메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

Enterprise Flex RIA 해부(17) : 플렉스 테스트하기

한빛미디어

|

2008-10-29

|

by HANBIT

9,949

제공 : 한빛 네트워크
저자 : Tony Hillerson
역자 : 채수원
원문 : Anatomy of an Enterprise Flex RIA Part 17: Testing Flex

지난 연재에서 우리는 플렉스 바인딩을 사용해서 뷰를 설정하려면 Cairngorm의 모델 로케이터(model locator)를 어떻게 사용할지에 대해 살펴보았었다. 이제 우리는 FlexUnit 으로 플렉스를 테스트하는 것과 테스트들을 자동화 하는 것에 대해 살펴보고자 한다.

우리는 애플리케이션의 퍼시스턴스 레이어(persistence layer) 를 단위 테스트 하기 위해TestNG를 어떻게 사용하는지 살펴봤었다. 플렉스는 FlexUnit 이라고 하는, 단위 테스트 프레임워크 또한 가지고 있다.

비주얼한 애플리케이션을 테스트하는 것은 그렇지 않은 코드를 테스트하는 것과 달리 결코 쉬운 일이 아니다. 플렉스 프레임워크는 테스트디렉터(Mercury TestDirector) 같은 자동화된 테스팅 제품들과 함께 사용하기 위한 자동화 클래스들을 가지고 있다. 머큐리 테스트디렉터(Mercury TestDirector) 는 애플리케이션에 대한 유저의 상호작용을 흉내 낼 수 있다. 이쯤에서 우리는, (유저의 동작이) 우리가 예상한 데로 발생하는 것은 몇 가지에 불과하다고 확신하겠지만, 그래도 대개는 FlexUnit 테스트들을 자동화 하는 방법의 예로 Ant를 사용한다.

[그림 21]은 우리가 살펴보게 될 파일들을 보여주고 있다.


[그림 21] Flex Unit 파일들

플렉스 애플리케이션, bookie_tests.mxml은 실행할 테스트 스위트들(test suites)을 정의하고 테스트들를 수행하기 위한 .swf 파일을 제공한다. Test디렉터리 밑의 BookieTests.as 는 테스트 스위트 하나를 포함하고 있다.

bookie_tests.mxml 내의 테스트 러너에 해당하는 코드는 아래와 같다.

    


private var runner:JUnitTestRunner;

private function test():void {
     status.text = "Testing...";
     runner = new JUnitTestRunner();
     runner.run(suite(), onTestComplete);
}

private function suite():TestSuite {
     var testSuite:TestSuite = new TestSuite();
 
     testSuite.addTest(BookieTests.suite());
 
     return testSuite;
}

private function onTestComplete():void {
     status.text = "Test complete, safe to close.";
     fscommand("quit");
}
...


...
애플리케이션이 로딩을 마치고 나면, test()를 호출한다. 이 메소드는 새로운 JUnitTestRunner 를 만들고 suite() 메소드에 의해 넘겨받은 TestSuite를 추가한다. suite()메소드는 BookieTests로부터 테스트 스위트를 넘겨준다. 자바 단위 테스트 프레임워크인 JUnit에 익숙한 사람이라면 누구나 이 프로세스를 알아볼 것이다.

상태 메시지를 표시하기 위한 우리가 텍스트 제어를 갖는 다는 것에 주목해라. 그 위에 있는 것이 BookieController이다. 여기 있는 컨트롤러를 포함시키는 것은, Cairngorm 커맨드와 대게 모델에 해당하는 애플리케이션의 부분들과의 상호작용 테스트를 가능케 해준다. (모델에 대해서는 잠시 뒤에 살펴 볼 예정이다.)

이런 식의 절차는 FlexUnit 테스트를 실행하는 표준 방식과는 살짝 다르다. JUnitTestRunner 또한 마찬가지로 표준 FlexUnit 테스트 러너와도 조금 다르다. 표준 테스트 러너는 인터페이스에 있는 테스트의 결과나 실패를 표시한다. (역주1) 그러나 우리 경우에는, 테스트가 실패할 경우 자동화된 빌드를 멈추게 하는 것에 좀 더 관심이 있다.

(역주1) 인터페이스에 선언된 fault() 와 result() 메소드의 호출 결과를 말한다.

JUnitTestRunner는 Ant 빌드의 일부로 실행된다는 점에 의존한다. Ant 빌드가 어떤 플렉스 단위 task를 시작했을 때, 서버를 열어 플렉스 테스트 애플리케이션이 접속하는 것을 기다리게 된다. 그리고는 테스트를 수행해서 실패하는 테스트가 있는지 없는지를 결정한다. 만일 실패하는 테스트가 있다면, Flex unit Ant task 는 에러와 함께 빌드를 멈추게 할 수 있다. 비록 실패로 인해 빌드가 중단되더라도 브라우저에는 어떤 결과도 표시되진 않는다. 이 한계를 피해가는 가능한 방법 하나는, 동일한 테스트 스위트들을 수행하는 다른 애플리케이션에서 표준 FlexUnit 러너를 실행하게 함으로써 실패하는 테스트들에 관한 정보를 얻는 것이다.

플렉스 테스트를 실행하는 Ant 빌드 파일(build.xml)에서 이에 해당 섹션은 아래와 같다.

    
    
         
         
         
         
         
         
    
    



    


"ant test-flex"를 실행하면 우선 빌드 디렉터리로 테스트 애플리케이션을 컴파일 한다. 그리고는 빌드 파일에 대한 논의 때 살펴봤었고, 파일의 앞부분에서 정의했던 flexunit custom task 를 호출한다. 이 task 는 컴파일된 테스트인 .swf 파일을 가리키고 있으며 로컬 시스템에 있는 .swf 파일을 여는 방법이 들어 있다. 우리는 플렉스 테스트가 실패하면 빌드도 실패하길 원한다는 내용 또한 명시해 놓았다.

bookie-ui 루트 디렉터리에서 "ant test-flex" 를 호출하거나 마찬가지로 the bookie-ui 디렉터리 혹은 프로젝트 루트 디렉터리에서 "mvn test"를 실행해 보길 바란다.

자동화된 빌드의 일부분으로써 유일하게 필요한 것은 브라우저 하나다. 그 브라우저는 시스템 내에서 사용 가능하고, .swf파일을 실행할 수 있으면 된다.

tests.BookieTests 에 들어 있는 테스트들을 살펴보자.
public static function suite():TestSuite {
     var testSuite:TestSuite = new TestSuite();
 
     testSuite.addTest(new BookieTests("testModelsAreSingletons"));
     testSuite.addTest(new BookieTests("testSignOutCommand"));
 
     return testSuite;
}
suite 메소드는 모든 테스트들이 추가되어 있고 실행준비가 되어있는 TestSuite를 반환한다. 테스트 애플리케이션은 이 메소드(suite)로부터 TestSuite를 얻게 된다. 우리가 갖고 있는 두 개의 테스트는 아래 보이는 것처럼 testModelsAreSingletons 과 testSignOutCommand 이다.
public function testModelsAreSingletons():void {
     var caughtBookieModelInstantiationError:Boolean;
     var caughtAdminModelInstantiationError:Boolean;
     var model:BookieModel;
     var adminModel:AdminModel;
 
     try {
           model = new BookieModel(null);
      } catch (e:Error) {
           caughtBookieModelInstantiationError = true;
      }
 
     try {
           adminModel = new AdminModel(null);
      } catch (e:Error) {
           caughtAdminModelInstantiationError = true;
      }
 
     assertTrue("Expected error instantiating singleton BookieModel", 
                caughtBookieModelInstantiationError);
     assertTrue("Expected error instantiating singleton AdminModel", 
                caughtAdminModelInstantiationError);
     assertUndefined(model)
     assertUndefined(adminModel);
 
 
     model = BookieModel.getInstance();
     adminModel = AdminModel.getInstance();
 
     assertNotUndefined(model)
     assertNotUndefined(adminModel)
 
}
만약 어떤 코드가 getInstance 호출을 통하지 않고 모델을 인스턴스화 하려 한다면 이 테스트는 확실하게 에러를 던진다. 이것은 모델 로케이터의 싱글턴 패턴을 강제한다.
public function testSignOutCommand():void {
     assertEquals(
          "Model should initialize state to SIGNED_OUT",
          model.currentState,
          BookieModel.SIGNED_OUT
     )
 
     // set state as if we were signed in
     model.currentState = BookieModel.SIGNED_IN;
 
     new SignOutEvent().dispatch();
     assertEquals(
          "Model should be SIGNED_OUT after sign out event.",
          model.currentState,
          BookieModel.SIGNED_OUT
     )
}
이 테스트는 작업이 끝난 뒤에 SignOutCommand 모델의 상태를 SIGNED_OUT 상수로 되돌려 놓는 것을 확실하게 만들어 준다. 나는 당신이 Cairngorm 상호작용들을 테스트 할 수 있다는 것을 보여주기 위해 이 커맨드를 선택했다. 서비스관련 상호작용은 JBoss 내부에서 실행되어야 하거나 해당 서비스들을 위한 Mock Object를 구현한 테스트를 필요로 할 것이다. 둘 다 할만한 작업이다. 여기서 우리가 갖고 있는 테스트들은 좋은 시작이고, 그 테스트들은 Ant를 사용해서 플렉스 테스트를 어떻게 실행할 것인지를 보여준다.

서비스들과 위임들, 컨트롤러들, 커맨드들, 그리고 모델들은, 눈에 잘 보이지 않은 작업(데이터에서 기인한 애플리케이션을 뚝딱 만들어내는 것 같은 작업)을 수행하는 것을 도와주는 요소들이다. 테스트들은 우리가 일어나길 예상하는 일들이 일어난다는 것을 확신할 수 있도록 돕는다. 다음에는, 사용자가 볼 수 있는 부분인 뷰(view)를 살펴볼 예정이다.

다음 연재는 애플리케이션의 플렉스 UI를 구축하는데 우리들이 좀더 가깝게 다가갈 수 있게 할 것이다. 언제든 전체 시리즈는 여기에서 찾아 볼 수 있다.
TAG :
댓글 입력
자료실

최근 본 책0